package cn.iocoder.yudao.module.system.service.hybase;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.util.enums.HybaseFieldType;
import com.trs.hybase.client.*;
import com.trs.hybase.client.params.ConnectParams;
import com.trs.hybase.client.params.OperationParams;
import com.trs.hybase.client.params.SearchParams;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class HyBaseServiceImpl implements HyBaseService {

    @Value("${hybase.url}")
    private String url;

    @Value("${hybase.username}")
    private String user;

    @Value("${hybase.password}")
    private String password;

    @Override
    public TRSConnection connection() {
        return new TRSConnection(url, user, password, new ConnectParams());
    }

    @Override
    public void close(TRSConnection connection) {
        if (connection != null) {
            connection.close();
            connection = null;
        }
    }


    @Override
    public void insert(String tableName, Map<String, Object> params) {
        TRSInputRecord inputRecord = new TRSInputRecord();
        params.forEach((k, v) -> {
            try {
                log.info(k + "==" + v);
                if (v instanceof Boolean) {
                    Boolean bool = (Boolean) v;
                    if (bool) {
                        inputRecord.addColumn(k, 0);
                    } else {
                        inputRecord.addColumn(k, 1);
                    }
                } else {
                    inputRecord.addColumn(k, v);
                }
            } catch (TRSException e) {
                log.info(e.getMessage() + String.format("%s=%s", k, v));
            }
        });
        this.insert(tableName, inputRecord);
    }

    @Override
    public void insert(String tableName, TRSInputRecord record) {
        List<TRSInputRecord> records = new ArrayList<>(1);
        records.add(record);
        this.insertBatch(tableName, records);
    }

    @Override
    public void insert(String tableName, List<Map<String, Object>> data) {
        List<TRSInputRecord> trsInputRecords = new ArrayList<>(data.size());
        for (Map<String, Object> map : data) {
            TRSInputRecord inputRecord = new TRSInputRecord();
            map.forEach((k, v) -> {
                try {
                    inputRecord.addColumn(k, v);
                } catch (TRSException e) {
                    throw new RuntimeException(e);
                }
            });
            trsInputRecords.add(inputRecord);
        }
        this.insertBatch(tableName, trsInputRecords);
    }

    @Override
    public void insertBatch(String tableName, List<TRSInputRecord> trsInputRecords) {
        TRSConnection connection = this.connection();
        try {
            connection.executeInsert(tableName, trsInputRecords);
        } catch (TRSException e) {
            log.error(e.getMessage());
        } finally {
            this.close(connection);
        }
    }

    @Override
    public void update(String tableName, TRSInputRecord inputRecord) {
        List<TRSInputRecord> records = new ArrayList<>(1);
        records.add(inputRecord);
        this.updateBatch(tableName, records);
    }

    @Override
    public void update(String tableName, Map<String, Object> params) {
        TRSInputRecord inputRecord = new TRSInputRecord();
        params.forEach((k, v) -> {
            try {
                log.info(k + "==" + v);
                inputRecord.addColumn(k, v);
            } catch (TRSException e) {
                log.info(String.format("update[%s:%s]:", k, v) + e.getMessage());
            }
        });
        this.update(tableName, inputRecord);
    }

    @Override
    public void updateBatch(String tableName, List<TRSInputRecord> trsInputRecords) {
        TRSConnection connection = this.connection();
        OperationParams newParams = new OperationParams();
        TRSReport report = new TRSReport();
        try {
            newParams.setProperty("unique.column.search", "true");
            newParams.setProperty("unique.column", "id");
            connection.executeUpdate(tableName, trsInputRecords, newParams, report);
            log.info("HyBase update success num:" + report.getUpdatedNum());
            log.error("HyBase update fail :" + report.getErrorNo());
            log.error("HyBase update fail info:" + report.getErrorMessage());
        } catch (TRSException e) {
            throw new RuntimeException(e);
        } finally {
            this.close(connection);
        }
    }

    @Override
    public boolean createTableRes(String tableName, List<String> list) {
        TRSConnection connection = this.connection();
        TRSDatabase trsDatabase = new TRSDatabase(tableName);
        List<TRSDatabaseColumn> columns = new ArrayList<>(list.size());
        list.forEach(columnName -> {
            TRSDatabaseColumn column = new TRSDatabaseColumn(columnName,
                    TRSDatabaseColumn.TYPE_PHRASE);
            if (columnName.equals("create_time") || columnName.equals("update_time")) {
                column = new TRSDatabaseColumn(columnName, TRSDatabaseColumn.TYPE_DATE);
            }
            columns.add(column);
        });
        try {
            trsDatabase.addColumn(new TRSDatabaseColumn("id", TRSDatabaseColumn.TYPE_CHAR));
            trsDatabase.setUniqueColumn("id");
            trsDatabase.addColumns(columns);
            connection.createDatabase(trsDatabase);
        } catch (TRSException e) {
            log.error("create table fail " + e.getMessage());
            return false;
        } finally {
            this.close(connection);
            return true;
        }
    }

    @Override
    public boolean deleteTable(String tableName) {
        TRSConnection connection = this.connection();
        Boolean res = true;
        try {
            connection.deleteDatabase(tableName);
        } catch (TRSException e) {
            log.error("delete table fail " + e.getMessage());
            res = false;
            return res;
        } finally {
            this.close(connection);
            return res;
        }
    }

    @Override
    public boolean createTable(String tableName, List<Map<String, Object>> fieldDOList) {
        TRSConnection connection = this.connection();
        TRSDatabase trsDatabase = new TRSDatabase(tableName);
        List<TRSDatabaseColumn> columns = new ArrayList<>(fieldDOList.size());
        fieldDOList.forEach(tableFieldDO -> {
            String columnName = (String)tableFieldDO.get("COLUMN_NAME");
            String columnType= (String) tableFieldDO.get("DATA_TYPE");
            TRSDatabaseColumn column = new TRSDatabaseColumn(
                    columnName,
                    HybaseFieldType.getDbType(columnType));
                    //columnName.equals("hybase_id") ? TRSDatabaseColumn.TYPE_CHAR : HybaseFieldType.getDbType(columnType));
            if (columnName.equals("create_time") || columnName.equals("update_time") || columnName.equals("pic_create_time")) {
                column = new TRSDatabaseColumn(columnName, TRSDatabaseColumn.TYPE_DATE);
            }
            columns.add(column);
        });
        Boolean res = true;
        try {
            trsDatabase.addColumns(columns);
            connection.createDatabase(trsDatabase);
        } catch (TRSException e) {
            res = false;
            log.error("create table fail " + e.getMessage());
            return res;
        } finally {
            this.close(connection);
            return res;
        }
    }

    @Override
    public String extractImageFeatures(File file) {
        TRSConnection connection = this.connection();
        return "";
    }

    @Override
    public long executeDeleteQuery(String DBName, Long id) {
        TRSConnection connection = this.connection();
        long result = 0;
        try {
            result = connection.executeDeleteQuery(DBName, "id:" + id);
        } catch (TRSException e) {
            log.error("delete query fail " + e.getMessage());
            return result;
        } finally {
            this.close(connection);
            return result;
        }
    }

    @Override
    public Map<String, Long> categoryQuery(String strSources, String query, String defaultColumn, String categoryColumn, long topNum) {
        TRSConnection connection = this.connection();
        try {
            TRSResultSet result = connection.categoryQuery(strSources, query, defaultColumn, categoryColumn, topNum);
            Map<String, Long> categoryMap = result.getCategoryMap();
            return categoryMap;
        } catch (TRSException e) {
            log.error("categoryQuery fail:" + e.getMessage());
            return new HashMap<>();
        } finally {
            connection.close();
        }
    }

    @Override
    public PageResult<Map<String, Object>> select(String tableName, String where, Long start, Long num, SearchParams searchParams) {
        TRSConnection connection = this.connection();
        PageResult<Map<String, Object>> pageResult = new PageResult<>();
        List<Map<String, Object>> list = new ArrayList<>();
        try {
            TRSResultSet rs = connection.executeSelect(tableName, where, start, num, searchParams);
            pageResult.setTotal(rs.getNumFound());
            for (int i = 0; i < rs.size(); i++) {
                rs.moveNext();
                TRSRecord trsRecord = rs.get();
                Map<String, Object> map = new HashMap<>();
                for (String column : trsRecord.getColumnNames()) {
                    map.put(column, trsRecord.getString(column));
                }
                list.add(map);
            }
            pageResult.setList(list);
            return pageResult;
        } catch (TRSException e) {
            log.error(e.getMessage());
            return new PageResult<>(0L);
        } finally {
            connection.close();
        }
    }

    /**
     * 修改单行记录
     *
     * @param tableName
     * @param id
     * @param map
     */
    @Override
    public void updateHybaseById(String tableName, Long id, Map<String, Object> map) {
        TRSConnection connection = this.connection();
        List<TRSInputRecord> newValues = new ArrayList<>();
        OperationParams params = new OperationParams();
        TRSReport report = new TRSReport();
        try {
            params.setProperty("unique.column.search", "true");
            params.setProperty("unique.column", "id");
            TRSInputRecord record = new TRSInputRecord();
            record.addColumn("id", id);
            map.keySet().forEach(key -> {
                try {
                    record.addColumn(key, map.get(key));

                } catch (TRSException e) {
                    e.printStackTrace();
                }
            });
            newValues.add(record);
            connection.executeUpdate(tableName, newValues, params, report);
        } catch (TRSException e) {
            e.printStackTrace();
        }

    }
}
